﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace config.view
{
    public partial class SimpleMappingCurveEditor : UserControl
    {
        private List<Point> controlPoints;
        private Ellipse selectedPoint;
        private bool isDragging = false;
        private const double PointRadius = 8;

        // 固定的X坐标位置
        private readonly double[] fixedXPositions = { 0, 20, 40, 60, 80, 100 };

        public SimpleMappingCurveEditor()
        {
            InitializeComponent();
            InitializeControlPoints();
            DrawMappingCurve();
        }

        private void InitializeControlPoints()
        {
            controlPoints = new List<Point>();

            // 初始化固定X位置的点，Y值从0到100线性分布
            for (int i = 0; i < fixedXPositions.Length; i++)
            {
                double y = (fixedXPositions[i] / 100.0) * 100; // 线性映射
                controlPoints.Add(new Point(fixedXPositions[i], y));
            }
        }

        private void DrawMappingCurve()
        {
            MappingCanvas.Children.Clear();

            double canvasWidth = MappingCanvas.ActualWidth;
            double canvasHeight = MappingCanvas.ActualHeight;

            if (canvasWidth <= 0 || canvasHeight <= 0) return;

            // 绘制背景网格
            DrawGrid(canvasWidth, canvasHeight);

            // 绘制坐标轴
            DrawAxes(canvasWidth, canvasHeight);

            // 绘制样条曲线
            DrawSplineCurve(canvasWidth, canvasHeight);

            // 绘制控制点
            DrawControlPoints(canvasWidth, canvasHeight);
        }

        private void DrawGrid(double width, double height)
        {
            // 绘制网格线
            for (int i = 0; i <= 10; i++)
            {
                double x = i * width / 10;
                double y = i * height / 10;

                // 垂直线
                Line verticalLine = new Line
                {
                    X1 = x,
                    X2 = x,
                    Y1 = 0,
                    Y2 = height,
                    Stroke = new SolidColorBrush(Color.FromArgb(0x20, 0x88, 0x88, 0x88)),
                    StrokeThickness = 1
                };
                MappingCanvas.Children.Add(verticalLine);

                // 水平线
                Line horizontalLine = new Line
                {
                    X1 = 0,
                    X2 = width,
                    Y1 = y,
                    Y2 = y,
                    Stroke = new SolidColorBrush(Color.FromArgb(0x20, 0x88, 0x88, 0x88)),
                    StrokeThickness = 1
                };
                MappingCanvas.Children.Add(horizontalLine);

                // 坐标标签
                if (i > 0 && i < 10)
                {
                    // X轴标签
                    TextBlock xLabel = new TextBlock
                    {
                        Text = (i * 10).ToString(),
                        Foreground = new SolidColorBrush(Color.FromArgb(0x80, 0xCC, 0xCC, 0xCC)),
                        FontSize = 9
                    };
                    Canvas.SetLeft(xLabel, x - 8);
                    Canvas.SetTop(xLabel, height - 15);
                    MappingCanvas.Children.Add(xLabel);

                    // Y轴标签
                    TextBlock yLabel = new TextBlock
                    {
                        Text = (100 - i * 10).ToString(),
                        Foreground = new SolidColorBrush(Color.FromArgb(0x80, 0xCC, 0xCC, 0xCC)),
                        FontSize = 9
                    };
                    Canvas.SetLeft(yLabel, 5);
                    Canvas.SetTop(yLabel, y - 8);
                    MappingCanvas.Children.Add(yLabel);
                }
            }

            // 绘制固定X位置的垂直线
            foreach (double xPos in fixedXPositions)
            {
                double x = (xPos / 100.0) * width;

                Line fixedLine = new Line
                {
                    X1 = x,
                    X2 = x,
                    Y1 = 0,
                    Y2 = height,
                    Stroke = new SolidColorBrush(Color.FromArgb(0x40, 0x21, 0x96, 0xF3)),
                    StrokeThickness = 1,
                    StrokeDashArray = new DoubleCollection { 2, 2 }
                };
                MappingCanvas.Children.Add(fixedLine);

                // 固定位置标签
                TextBlock fixedLabel = new TextBlock
                {
                    Text = xPos.ToString(),
                    Foreground = new SolidColorBrush(Color.FromArgb(0x80, 0x21, 0x96, 0xF3)),
                    FontSize = 10,
                    FontWeight = FontWeights.Bold
                };
                Canvas.SetLeft(fixedLabel, x - 10);
                Canvas.SetTop(fixedLabel, height - 25);
                MappingCanvas.Children.Add(fixedLabel);
            }
        }

        private void DrawAxes(double width, double height)
        {
            // X轴
            Line xAxis = new Line
            {
                X1 = 0,
                X2 = width,
                Y1 = height,
                Y2 = height,
                Stroke = new SolidColorBrush(Color.FromArgb(0x80, 0xCC, 0xCC, 0xCC)),
                StrokeThickness = 2
            };
            MappingCanvas.Children.Add(xAxis);

            // Y轴
            Line yAxis = new Line
            {
                X1 = 0,
                X2 = 0,
                Y1 = 0,
                Y2 = height,
                Stroke = new SolidColorBrush(Color.FromArgb(0x80, 0xCC, 0xCC, 0xCC)),
                StrokeThickness = 2
            };
            MappingCanvas.Children.Add(yAxis);

            // 坐标轴标签
            TextBlock xLabel = new TextBlock
            {
                Text = "输入值 (0-100)",
                Foreground = new SolidColorBrush(Color.FromArgb(0x80, 0xCC, 0xCC, 0xCC)),
                FontSize = 10
            };
            Canvas.SetLeft(xLabel, width / 2 - 30);
            Canvas.SetTop(xLabel, height - 25);
            MappingCanvas.Children.Add(xLabel);

            TextBlock yLabel = new TextBlock
            {
                Text = "输出值 (0-100)",
                Foreground = new SolidColorBrush(Color.FromArgb(0x80, 0xCC, 0xCC, 0xCC)),
                FontSize = 10,
                RenderTransform = new RotateTransform(-90)
            };
            Canvas.SetLeft(yLabel, -height / 2 + 30);
            Canvas.SetTop(yLabel, height / 2 - 30);
            MappingCanvas.Children.Add(yLabel);
        }

        private void DrawSplineCurve(double width, double height)
        {
            if (controlPoints.Count < 2) return;

            // 准备控制点数据（在画布坐标中）
            List<Point> canvasPoints = new List<Point>();
            foreach (var point in controlPoints)
            {
                canvasPoints.Add(ValueToCanvasPoint(point, width, height));
            }

            // 使用样条曲线拟合
            List<Point> splinePoints = CalculateCatmullRomSpline(canvasPoints, 50);

            // 绘制样条曲线
            Polyline curve = new Polyline
            {
                Stroke = new SolidColorBrush(Color.FromRgb(0x21, 0x96, 0xF3)),
                StrokeThickness = 3,
                Points = new PointCollection(splinePoints)
            };
            MappingCanvas.Children.Add(curve);

            // 绘制直线段（用于参考）
            for (int i = 0; i < canvasPoints.Count - 1; i++)
            {
                Line segment = new Line
                {
                    X1 = canvasPoints[i].X,
                    Y1 = canvasPoints[i].Y,
                    X2 = canvasPoints[i + 1].X,
                    Y2 = canvasPoints[i + 1].Y,
                    Stroke = new SolidColorBrush(Color.FromArgb(0x40, 0x21, 0x96, 0xF3)),
                    StrokeThickness = 1,
                    StrokeDashArray = new DoubleCollection { 4, 2 }
                };
                MappingCanvas.Children.Add(segment);
            }
        }

        private void DrawControlPoints(double width, double height)
        {
            for (int i = 0; i < controlPoints.Count; i++)
            {
                Point valuePoint = controlPoints[i];
                Point canvasPoint = ValueToCanvasPoint(valuePoint, width, height);

                // 控制点
                Ellipse point = new Ellipse
                {
                    Width = PointRadius * 2,
                    Height = PointRadius * 2,
                    Fill = i == 0 || i == controlPoints.Count - 1 ?
                           new SolidColorBrush(Color.FromRgb(0xF4, 0x43, 0x36)) : // 起点和终点用红色
                           new SolidColorBrush(Color.FromRgb(0x4C, 0xAF, 0x50)),   // 中间点用绿色
                    Stroke = Brushes.White,
                    StrokeThickness = 1,
                    Tag = i, // 存储点的索引
                    Cursor = Cursors.Hand // 鼠标悬停时显示手型光标
                };

                // 为控制点添加鼠标事件
                point.MouseLeftButtonDown += ControlPoint_MouseLeftButtonDown;
                point.MouseLeftButtonUp += ControlPoint_MouseLeftButtonUp;
                point.MouseLeave += ControlPoint_MouseLeave;

                Canvas.SetLeft(point, canvasPoint.X - PointRadius);
                Canvas.SetTop(point, canvasPoint.Y - PointRadius);
                MappingCanvas.Children.Add(point);

                // 坐标标签
                TextBlock label = new TextBlock
                {
                    Text = $"({valuePoint.X:0}, {valuePoint.Y:0})",
                    Foreground = Brushes.White,
                    FontSize = 8,
                    Background = new SolidColorBrush(Color.FromArgb(0xCC, 0x33, 0x33, 0x33)),
                    Padding = new Thickness(3, 1, 3, 1)
                };

                Canvas.SetLeft(label, canvasPoint.X - 15);
                Canvas.SetTop(label, canvasPoint.Y - 15);
                MappingCanvas.Children.Add(label);
            }
        }

        private Point ValueToCanvasPoint(Point valuePoint, double width, double height)
        {
            // 将数值坐标 (0-100, 0-100) 转换为画布坐标
            double x = (valuePoint.X / 100.0) * width;
            double y = height - (valuePoint.Y / 100.0) * height; // Y轴翻转
            return new Point(x, y);
        }

        private Point CanvasToValuePoint(Point canvasPoint, double width, double height)
        {
            // 将画布坐标转换为数值坐标 (0-100, 0-100)
            double x = (canvasPoint.X / width) * 100;
            double y = 100 - (canvasPoint.Y / height) * 100; // Y轴翻转
            return new Point(
                Math.Max(0, Math.Min(100, x)),
                Math.Max(0, Math.Min(100, y))
            );
        }

        private List<Point> CalculateCatmullRomSpline(List<Point> controlPoints, int segmentsPerPoint)
        {
            List<Point> result = new List<Point>();

            if (controlPoints.Count < 2)
                return result;

            // 如果只有2个点，直接绘制直线
            if (controlPoints.Count == 2)
            {
                result.Add(controlPoints[0]);
                for (int i = 1; i <= segmentsPerPoint; i++)
                {
                    double t = i / (double)segmentsPerPoint;
                    double x = controlPoints[0].X + t * (controlPoints[1].X - controlPoints[0].X);
                    double y = controlPoints[0].Y + t * (controlPoints[1].Y - controlPoints[0].Y);
                    result.Add(new Point(x, y));
                }
                return result;
            }

            // 添加第一个点
            result.Add(controlPoints[0]);

            // 对每对控制点之间进行插值
            for (int i = 0; i < controlPoints.Count - 1; i++)
            {
                Point p0, p1, p2, p3;

                // 计算控制点
                if (i == 0)
                {
                    // 第一个段，使用镜像点
                    p0 = controlPoints[0];
                    p1 = controlPoints[0];
                    p2 = controlPoints[1];
                    p3 = controlPoints.Count > 2 ? controlPoints[2] : controlPoints[1]; // 安全检查
                }
                else if (i == controlPoints.Count - 2)
                {
                    // 最后一个段，使用镜像点
                    p0 = controlPoints[i - 1];
                    p1 = controlPoints[i];
                    p2 = controlPoints[i + 1];
                    p3 = controlPoints[i + 1];
                }
                else
                {
                    // 中间段
                    p0 = controlPoints[i - 1];
                    p1 = controlPoints[i];
                    p2 = controlPoints[i + 1];
                    p3 = controlPoints[i + 2];
                }

                // 生成样条曲线上的点
                for (int j = 1; j <= segmentsPerPoint; j++)
                {
                    double t = j / (double)segmentsPerPoint;
                    Point point = CalculateCatmullRomPoint(t, p0, p1, p2, p3);
                    result.Add(point);
                }
            }

            return result;
        }

        private Point CalculateCatmullRomPoint(double t, Point p0, Point p1, Point p2, Point p3)
        {
            // Catmull-Rom 样条公式
            double t2 = t * t;
            double t3 = t2 * t;

            double x = 0.5 * ((2 * p1.X) +
                             (-p0.X + p2.X) * t +
                             (2 * p0.X - 5 * p1.X + 4 * p2.X - p3.X) * t2 +
                             (-p0.X + 3 * p1.X - 3 * p2.X + p3.X) * t3);

            double y = 0.5 * ((2 * p1.Y) +
                             (-p0.Y + p2.Y) * t +
                             (2 * p0.Y - 5 * p1.Y + 4 * p2.Y - p3.Y) * t2 +
                             (-p0.Y + 3 * p1.Y - 3 * p2.Y + p3.Y) * t3);

            return new Point(x, y);
        }

        // 控制点鼠标事件 - 修复版本
        private void ControlPoint_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (sender is Ellipse ellipse && ellipse.Tag is int index)
            {
                selectedPoint = ellipse;
                isDragging = true;

                // 捕获鼠标，确保即使鼠标移出控制点也能继续接收事件
                ellipse.CaptureMouse();

                e.Handled = true; // 阻止事件冒泡

                // 添加画布的鼠标左键释放事件处理
                MappingCanvas.MouseLeftButtonUp += MappingCanvas_MouseLeftButtonUp;
                MappingCanvas.MouseMove += MappingCanvas_MouseMove;
            }
        }

        private void ControlPoint_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            EndDragging();
            e.Handled = true;
        }

        private void ControlPoint_MouseLeave(object sender, MouseEventArgs e)
        {
            // 如果鼠标离开控制点但仍在拖动中，不执行任何操作
            // 因为我们已经捕获了鼠标，所以会继续接收事件
        }

        private void MappingCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            // 如果在画布上释放鼠标按钮，也结束拖动
            EndDragging();
        }

        private void MappingCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            Point mousePos = e.GetPosition(MappingCanvas);
            double canvasWidth = MappingCanvas.ActualWidth;
            double canvasHeight = MappingCanvas.ActualHeight;

            if (canvasWidth <= 0 || canvasHeight <= 0) return;

            // 更新坐标显示
            Point valuePoint = CanvasToValuePoint(mousePos, canvasWidth, canvasHeight);
            CoordinateText.Text = $"坐标: ({valuePoint.X:0}, {valuePoint.Y:0})";

            // 拖动控制点
            if (isDragging && selectedPoint != null && selectedPoint.Tag is int index && e.LeftButton == MouseButtonState.Pressed)
            {
                Point newValuePoint = CanvasToValuePoint(mousePos, canvasWidth, canvasHeight);

                // X坐标固定，只允许调整Y坐标
                newValuePoint.X = controlPoints[index].X; // 保持X坐标不变
                newValuePoint.Y = Math.Max(0, Math.Min(100, newValuePoint.Y)); // 限制Y坐标在0-100范围内

                controlPoints[index] = newValuePoint;
                DrawMappingCurve();
            }
            else if (isDragging && e.LeftButton == MouseButtonState.Released)
            {
                // 如果鼠标按钮已经释放，但isDragging仍然是true，结束拖动
                EndDragging();
            }
        }

        private void EndDragging()
        {
            if (isDragging)
            {
                isDragging = false;

                if (selectedPoint != null)
                {
                    // 释放鼠标捕获
                    selectedPoint.ReleaseMouseCapture();
                    selectedPoint = null;
                }

                // 移除画布的事件处理
                MappingCanvas.MouseLeftButtonUp -= MappingCanvas_MouseLeftButtonUp;
                MappingCanvas.MouseMove -= MappingCanvas_MouseMove;
            }
        }

        // 按钮事件处理
        private void ResetButton_Click(object sender, RoutedEventArgs e)
        {
            InitializeControlPoints();
            DrawMappingCurve();
        }

        private void ApplyButton_Click(object sender, RoutedEventArgs e)
        {
            string mappingInfo = "当前映射曲线设置:\n";
            foreach (var point in controlPoints)
            {
                mappingInfo += $"({point.X:0}, {point.Y:0})\n";
            }

            MessageBox.Show(mappingInfo, "映射曲线已应用",
                MessageBoxButton.OK, MessageBoxImage.Information);
        }

        // 获取当前映射曲线（供外部使用）
        public List<Point> GetMappingCurve()
        {
            return new List<Point>(controlPoints);
        }

        // 设置映射曲线（供外部使用）
        public void SetMappingCurve(List<Point> points)
        {
            if (points != null && points.Count == fixedXPositions.Length)
            {
                // 确保X坐标与固定位置匹配
                for (int i = 0; i < points.Count; i++)
                {
                    if (Math.Abs(points[i].X - fixedXPositions[i]) > 0.001)
                    {
                        MessageBox.Show("提供的映射曲线X坐标与固定位置不匹配", "错误",
                            MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }
                }

                controlPoints = new List<Point>(points);
                DrawMappingCurve();
            }
            else
            {
                MessageBox.Show($"映射曲线必须包含 {fixedXPositions.Length} 个点", "错误",
                    MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        // 当Canvas大小改变时重绘曲线
        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            base.OnRenderSizeChanged(sizeInfo);
            DrawMappingCurve();
        }

    }
}